#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <cstring>

#define PATH "."
#define FILENAME "fifo"
#define EXIT_ERR(msg)                  \
    do                                 \
    {                                  \
        std::cerr << msg << std::endl; \
        exit(1);                       \
    } while (0)

class FifoHandler
{
public:
    FifoHandler(const std::string &path = PATH, const std::string &name = FILENAME, bool is_server = true)
        : _path(path), _name(name), _fd(-1), _is_server(is_server)
    {
        _fifoname = _path + "/" + _name;

        if (_is_server)
        {
            // 服务端：创建FIFO（若不存在）
            umask(0);
            if (mkfifo(_fifoname.c_str(), 0666) < 0 && errno != EEXIST)
            {
                EXIT_ERR("Failed to create FIFO: " << strerror(errno));
            }
            std::cout << "FIFO is ready (created or already exists)" << std::endl;
        }
        else
        {
            // 客户端：仅检查FIFO是否存在
            if (access(_fifoname.c_str(), F_OK) < 0)
            {
                EXIT_ERR("FIFO not found: " << strerror(errno));
            }
            std::cout << "Client: FIFO exists, ready to use" << std::endl;
        }
    }

    // 打开FIFO用于读取（阻塞等待写端）
    void OpenForRead()
    {
        _fd = open(_fifoname.c_str(), O_RDONLY);
        if (_fd < 0)
        {
            EXIT_ERR("Failed to open FIFO for reading: " << strerror(errno));
        }
        std::cout << "FIFO opened for reading" << std::endl;
    }

    // 打开FIFO用于写入（阻塞等待读端）
    void OpenForWrite()
    {
        _fd = open(_fifoname.c_str(), O_WRONLY);
        if (_fd < 0)
        {
            EXIT_ERR("Failed to open FIFO for writing: " << strerror(errno));
        }
        std::cout << "FIFO opened for writing" << std::endl;
    }

    // 写入数据（需先调用OpenForWrite）
    bool Write(const std::string &msg)
    {
        if (_fd < 0)
        {
            EXIT_ERR("FIFO not opened for writing");
            return false;
        }
        ssize_t number = write(_fd, msg.c_str(), msg.size());
        if (number < 0)
        {
            EXIT_ERR("Failed to write to FIFO: " << strerror(errno));
            return false;
        }
        return true;
    }

    // 单次读取：读取一条消息（需先调用OpenForRead）
    ssize_t Read(char *buffer, size_t max_len)
    {
        if (_fd < 0)
        {
            EXIT_ERR("FIFO not opened for reading");
            return -1;
        }

        // 读取数据（最多读取max_len-1字节，留一个位置给'\0'）
        ssize_t number = read(_fd, buffer, max_len - 1);
        if (number < 0)
        {
            EXIT_ERR("Failed to read from FIFO: " << strerror(errno));
            return -1;
        }
        else if (number == 0) // 读端关闭，read返回0
        {
            std::cout << "Read end closed, exit" << std::endl;
            return 0;
        }

        buffer[number] = '\0';
        return number;
    }

    void Close()
    {
        if (_fd != -1)
        {
            close(_fd);
            _fd = -1;
            std::cout << (_is_server ? "Server" : "Client") << ": FIFO closed" << std::endl;
        }
    }

    ~FifoHandler()
    {
        // 关闭FIFO
        Close(); // 无论角色，都关闭文件描述符
        // 通munication结束后删除FIFO
        if (_is_server)
        {
            if (unlink(_fifoname.c_str()) == 0)
            {
                std::cout << "FIFO removed" << std::endl;
            }
            else
            {
                std::cerr << "Failed to remove FIFO: " << strerror(errno) << std::endl;
            }
        }
        // 客户端：不执行unlink
    }

private:
    std::string _path;     // FIFO路径
    std::string _name;     // FIFO文件名
    std::string _fifoname; // FIFO完整路径
    int _fd;               // 文件描述符
    bool _is_server;       // 角色标识：true为服务端，false为客户端
};

// class FileOperation
// {
// public:
//     FileOperation(const std::string &path, const std::string &name) : _path(path), _name(name), _fd(-1)
//     {
//         _fifoname = _path + "/" + _name;
//     }

//     void OpenForRead()
//     {
//         // 打开FIFO for reading
//         // write方没有执行open的时候, read方就要在open内部进行阻塞, 等待read端打开, open才会返回
//         _fd = open(FILEName, O_RDONLY);
//         if (_fd < 0)
//         {
//             std::cerr << "Failed to open FIFO" << std::endl;
//             exit(2);
//         }
//     }

//     void OpenForWrite()
//     {
//         // Open the FIFO for writing
//         _fd = open(FILEName, O_WRONLY);
//         if (_fd < 0)
//         {
//             std::cerr << "Failed to open FIFO" << std::endl;
//             exit(2);
//         }
//         std::cout << "FIFO opened for writing" << std::endl;
//     }

//     void Write()
//     {
//         // Read messages from the user and write them to the FIFO
//         while (true)
//         {
//             std::cout << "Enter message to send: ";
//             std::string message;
//             std::getline(std::cin, message);

//             if (message == "q_q")
//             {
//                 break;
//             }

//             ssize_t number = write(_fd, message.c_str(), message.size());
//             if (number < 0)
//             {
//                 std::cerr << "Failed to write to FIFO" << std::endl;
//                 exit(3);
//             }
//         }
//     }

//     void Read()
//     {
//         // 循环读取数据
//         char buffer[1024];
//         while (true)
//         {
//             // 读取数据
//             ssize_t number = read(_fd, buffer, sizeof(buffer) - 1);

//             if (number < 0)
//             {
//                 std::cerr << "Failed to read from FIFO" << std::endl;
//                 exit(3);
//             }
//             else if (number == 0) // 写端关闭，read返回0
//             {
//                 std::cout << "Write end closed, exit" << std::endl;
//                 break;
//             }

//             buffer[number] = '\0';
//             std::cout << "client says: " << buffer << std::endl;
//         }
//     }

//     void Close()
//     {
//         if (_fd > 0)
//             close(_fd);
//     }

//     ~FileOperation()
//     {
//         Close();
//     }

// private:
//     std::string _path;
//     std::string _name;
//     std::string _fifoname;
//     int _fd;
// };